(function (win) {
  document = win.document;
  win.CrazyCircuit = {
    speed: 0.1,
    intervalMilliSecond: 8,
    currentMenu: "",
    stages: ["intro", "start", "s1", "s2", "s3"],
    doc: null,
    msg: null,
    power: null,
    colorList: [
      "HotPink",
      "DeepSkyBlue",
      "SpringGreen",
      "Gold",
      "DarkOrange",
      "Indigo",
    ],
    instanceArray: [],

    show(id) {
      document.getElementById(id) &&
        (document.getElementById(id).style.display = "block");
    },
    hide(id) {
      document.getElementById(id) &&
        (document.getElementById(id).style.display = "none");
    },
    toggle(id) {
      let dom = document.getElementById(id);
      if (dom) {
        dom.style.display === "none" ? this.show(id) : this.hide(id);
      }
    },
    navigateTo(id) {
      this.currentMenu = id;
      this.clear();
      if (id === "main") {
        this.show("main");
        this.show("menu");
        this.hide("back");
        this.hide("start");
        this.stages.forEach(this.hide);
      } else {
        this.show(id);
        this.show("back");
        this.hide("menu");
        this.hide("main");
        if (id != "intro") {
          this.show("start");
        }
      }
    },
    toggleSwitch(dom) {
      if (dom.className.indexOf("off") > -1) {
        dom.classList.remove("cc-switch-off");
      } else {
        dom.classList.add("cc-switch-off");
      }
    },
    clear() {
      this.instanceArray.forEach((item) => {
        if (item) {
          item.k && item.k.remove();
          item.kInterval && clearInterval(item.kInterval);
        }
      });
      this.instanceArray.length = 0;
    },
    start() {
      if (this.instanceArray.length === 0) {
        this.resolveMultiPlayground();
      }
      this.instanceArray.forEach((instance, index) => {
        if (!instance.k) {
          let color = this.colorList[index % this.colorList.length];
          instance.k = this.createK(instance.playground, color, index);
        }
        instance.k.style.left = parseFloat(this.power.style.left) + 2.4 + "rem";
        instance.k.style.top = parseFloat(this.power.style.top) + 0.5 + "rem";
        instance.k.style.opacity = 1;
        this.startK(instance);
      });
    },
    createK(playground, color, index) {
      let ele = this.doc.createElement("div");
      ele.className = "cc-electron";
      ele.style["box-shadow"] = `0 0 1rem ${color}`;
      ele.style["animation-name"] = `blink-electron-${index}`;
      playground.appendChild(ele);
      return ele;
    },
    resolveMultiPlayground() {
      let win = top.frames[this.currentMenu];
      this.doc = win.document;
      this.power = this.doc.getElementById("power");
      let playgrounds = this.doc.getElementsByClassName("cc-playground");
      [...playgrounds].forEach((p) => this.collectPath(p));
    },
    collectPath(playground) {
      let instance = {};
      instance.playground = playground;
      instance.kPath = [];
      instance.kPathTypes = [];
      instance.kIndex = 0;
      let elements = [...playground.children];
      for (let ele of elements) {
        if (ele.localName && ele.localName.indexOf("cc") > -1) {
          let e = ele.children[0];
          let leftA = e.style.left,
            topA = e.style.top,
            width = e.style.width,
            direction = e.getAttribute("direction");
          if (!direction) continue;
          instance.kPathTypes.push(e.getAttribute("type"));
          if (direction == "u" || direction == "d") {
            // 解析旋转的情况
            let leftB = leftA,
              topB;
            if (direction == "u") {
              // 向上
              topB = parseFloat(topA) - parseFloat(width) + "rem";
            } else {
              // 向下
              topB = parseFloat(topA) + parseFloat(width) + "rem";
            }
            instance.kPath.push([
              { top: topA, left: leftA },
              { top: topB, left: leftB },
            ]);
          } else {
            /* 横向需要判断运动方向，此时用direction属性做判断
              direction取值：u(上)d(下)l(左))r(右)
            */
            let topB = topA,
              leftB;
            if (direction == "l") {
              // 向左
              leftB = parseFloat(leftA) - parseFloat(width) + "rem";
            } else {
              // 向右
              leftB = parseFloat(leftA) + parseFloat(width) + "rem";
            }
            instance.kPath.push([
              { top: topA, left: leftA },
              { top: topB, left: leftB },
            ]);
          }
        }
      }
      this.instanceArray.push(instance);
      console.log(this.instanceArray, "instanceArray");
    },
    startK(instance) {
      if (instance.kInterval) {
        clearInterval(instance.kInterval);
      }
      if (instance.kIndex >= instance.kPath.length) {
        return;
      }
      instance.kInterval = setInterval(() => {
        try {
          let kPoints = instance.kPath[instance.kIndex],
            kPointA = kPoints[0],
            kPointB = kPoints[1];
          let kTop = parseFloat(instance.k.style.top),
            topA = parseFloat(kPointA.top),
            topB = parseFloat(kPointB.top);
          let kLeft = parseFloat(instance.k.style.left),
            leftA = parseFloat(kPointA.left),
            leftB = parseFloat(kPointB.left);
          /* 需要处理两种情况，在线段的中间、两侧
            1、如果在中间，只要使点的朝终点的方向运动
            2、如果在起点之前，需要先使点运动到起点，随后参照1
            3、如果在终点之后，则无法处理
            */
          if (topA == topB) {
            // 横向运动
            if (leftA < leftB) {
              // 从左往右
              if (kLeft < leftB) {
                if (leftB - kLeft < this.speed) {
                  this.nextK(instance);
                  return;
                }
                instance.k.style.left = kLeft + this.speed + "rem";
              } else {
                throw new Error(
                  `unexpected left error: ${kLeft}, ${leftA}, ${leftB}`
                );
              }
            } else {
              // 从右往左
              if (kLeft > leftA) {
                if (kLeft - leftA < this.speed) {
                  this.nextK(instance);
                  return;
                }
                instance.k.style.left = kLeft - this.speed + "rem";
              } else {
                throw new Error(
                  `unexpected left error: ${kLeft}, ${leftA}, ${leftB}`
                );
              }
            }
          } else {
            // 纵向运动
            if (topA < topB) {
              // 从下往上
              if (kTop < topB) {
                if (topB - kTop < this.speed) {
                  this.nextK();
                  return;
                }
                instance.k.style.top = kTop + this.speed + "rem";
              } else {
                throw new Error(
                  `unexpected top error:, ${kTop}, ${topA}, ${topB}`
                );
              }
            } else {
              // 从上往下
              if (kTop > topA) {
                if (kTop - topA < this.speed) {
                  this.nextK();
                  return;
                }
                instance.k.style.top = kTop - this.speed + "rem";
              } else {
                throw new Error(
                  `unexpected top error: ${kTop}, ${topA}, ${topB}`
                );
              }
            }
          }
        } catch (e) {
          console.warn(e);
          this.nextK(instance);
        }
      }, this.intervalMilliSecond);
    },
    nextK(instance) {
      clearInterval(instance.kInterval);
      let kIndexNext = instance.kIndex + 1;
      if (kIndexNext == instance.kPath.length) {
        instance.k.style.opacity = 0;
        // mdui.alert("complete!");
        this.finish(instance);
        return;
      }
      let type = instance.kPathTypes[kIndexNext];
      let dom = [...instance.playground.children].filter(
        (item) => item.localName && item.localName.indexOf("cc") > -1
      )[kIndexNext].children[0];
      switch (type) {
        case "switch":
          if (dom.className.indexOf("off") > -1) {
            setTimeout(() => {
              this.nextK(instance);
            }, 500);
          } else {
            instance.k.style.opacity = 0;
            instance.kIndex++;
            this.startK(instance);
          }
          break;
        case "bulb":
          instance.k.style.opacity = 0;
          if (dom.className.indexOf("on") == -1) {
            dom.classList.add("cc-bulb-on");
          }
          instance.kIndex++;
          this.startK(instance);
          break;
        case "resistance":
          instance.k.style.opacity = 0;
          if (dom.className.indexOf("blink") == -1) {
            dom.classList.add("cc-resistance-blink");
          }
          instance.kIndex++;
          this.startK(instance);
          break;
        case "heart":
        case "tree":
          instance.k.style.opacity = 0;
          if (dom.className.indexOf("-on") == -1) {
            dom.classList.add(`cc-${type}-on`);
          }
          instance.kIndex++;
          this.startK(instance);
          break;
        default:
          instance.k.style.opacity = 1;
          instance.kIndex++;
          this.startK(instance);
          break;
      }
    },
    finish(instance) {
      instance.kIndex = 0;
      instance.k.style.left = parseFloat(this.power.style.left) + 2.4 + "rem";
      instance.k.style.top = parseFloat(this.power.style.top) + 0.5 + "rem";
      instance.k.style.opacity = 1;
      this.startK(instance);
    },
  };
})(window);
